package services

import (
	"context"
	"github.com/golang/protobuf/ptypes/empty"
	"github.com/golang/protobuf/ptypes/wrappers"
	context2 "kop/framework/context"
	"kop/framework/errors"
	"kop/modules/award/models"
	"kop/pb"
	"kop/pb/service"

	captainC "kop/modules/captain/client"
	guildC "kop/modules/guild/client"
	mailC "kop/modules/mail/client"
	roleC "kop/modules/role/client"
)

type GuildService struct {
	context2.Context
}

func (s *GuildService) GetGuilds(ctx context.Context, req *wrappers.Int32Value) (*pb.Guilds, error) {

	return guildC.GetGuilds(s.GetServerID(ctx), req.Value)
}

func (s *GuildService) RandGuilds(ctx context.Context, req *empty.Empty) (*pb.Guilds, error) {

	return guildC.GuildService.RandGuilds(ctx, req)
}

func (s *GuildService) RandJoin(ctx context.Context, _ *empty.Empty) (*wrappers.BoolValue, error) {

	var reply wrappers.BoolValue

	var err error
	reply.Value, err = guildC.RandJoin(s.GetRoleID(ctx), s.GetServerID(ctx))
	return &reply, err
}

func (s *GuildService) GetGuild(ctx context.Context, req *wrappers.Int32Value) (*pb.GuildReply, error) {

	var reply pb.GuildReply

	var serverID = s.GetServerID(ctx)

	var err error
	reply.Guild, err = guildC.GetGuild(serverID, req.Value)

	return &reply, err
}

func (s *GuildService) MyGuild(ctx context.Context, req *empty.Empty) (*pb.GuildReply, error) {

	var reply pb.GuildReply

	var roleID = s.GetRoleID(ctx)
	var serverID = s.GetServerID(ctx)
	var guildID = s.GetGuildID(ctx)

	if guildID == 0 {
		return &reply, nil
	}

	var err error
	if reply.Guild, err = guildC.MyGuild(roleID, serverID, guildID); err != nil {
		return &reply, err
	}

	if reply.Members, err = guildC.Members(serverID, guildID); err != nil {
		return &reply, err
	}

	if res, err := guildC.GuildService.DailyQuest(ctx, req); err != nil {
		return &reply, err
	} else {
		reply.DailyQuests = res.DailyQuests
	}

	reply.Notice = guildC.GetNotice(guildID, serverID)

	return &reply, nil
}

func (s *GuildService) Create(ctx context.Context, req *pb.GuildCreateRequest) (*pb.GuildReply, error) {

	var reply pb.GuildReply

	var roleID = s.GetRoleID(ctx)
	var serverID = s.GetServerID(ctx)

	if len(req.Name) > 21 {
		return &reply, errors.ParamError
	}

	if len(req.Declaration) > 120 {
		return &reply, errors.ParamError
	}

	var err error
	if reply.Guild, err = guildC.Create(roleC.GetRole(roleID), req); err != nil {
		return &reply, err
	}

	if reply.Members, err = guildC.Members(serverID, reply.Guild.GuildID); err != nil {
		return &reply, err
	}

	reply.Notice = guildC.GetNotice(reply.Guild.GuildID, serverID)
	return &reply, nil
}

func (s *GuildService) SetName(ctx context.Context, req *pb.GuildSetNameRequest) (*pb.Guild, error) {

	return guildC.GuildService.SetName(ctx, req)
}

func (s *GuildService) SetNotice(ctx context.Context, req *wrappers.StringValue) (*empty.Empty, error) {

	return guildC.GuildService.SetNotice(ctx, req)
}

func (s *GuildService) SetAutoJoin(ctx context.Context, req *pb.GuildSetAutoJoinRequest) (*pb.Guild, error) {

	return guildC.GuildService.SetAutoJoin(ctx, req)
}

func (s *GuildService) Quit(ctx context.Context, req *empty.Empty) (*wrappers.Int32Value, error) {

	return guildC.GuildService.Quit(ctx, req)
}

func (s *GuildService) Dissolve(ctx context.Context, req *empty.Empty) (*wrappers.Int32Value, error) {

	return guildC.GuildService.Dissolve(ctx, req)
}

func (s *GuildService) SetElite(ctx context.Context, req *wrappers.Int32Value) (*pb.GuildMember, error) {

	return guildC.GuildService.SetElite(ctx, req)
}

func (s *GuildService) SetVicePresident(ctx context.Context, req *wrappers.Int32Value) (*pb.GuildMember, error) {

	return guildC.GuildService.SetVicePresident(ctx, req)
}

func (s *GuildService) SetPresident(ctx context.Context, req *wrappers.Int32Value) (*pb.GuildMember, error) {

	return guildC.GuildService.SetPresident(ctx, req)
}

func (s *GuildService) SetMember(ctx context.Context, req *wrappers.Int32Value) (*pb.GuildMember, error) {

	return guildC.GuildService.SetMember(ctx, req)
}

func (s *GuildService) Kick(ctx context.Context, req *wrappers.Int32Value) (*empty.Empty, error) {

	return guildC.GuildService.Kick(ctx, req)
}

func (s *GuildService) Build(ctx context.Context, req *pb.GuildBuildRequest) (*pb.GuildBuildReply, error) {

	return guildC.GuildService.Build(ctx, req)
}

func (s *GuildService) GetApplies(ctx context.Context, req *wrappers.Int32Value) (*pb.Roles, error) {

	return guildC.GuildService.GetApplies(ctx, req)
}

func (s *GuildService) Apply(ctx context.Context, req *wrappers.Int32Value) (*empty.Empty, error) {

	var roleID = s.GetRoleID(ctx)

	if s.GetGuildID(ctx) > 0 {
		return &empty.Empty{}, errors.ParamError
	}

	var guild, err = guildC.GetGuild(s.GetServerID(ctx), req.Value)
	if err != nil {
		return &empty.Empty{}, err
	}

	if guild.AutoJoin {

		_, err = guildC.Join(roleC.GetRole(roleID), req.Value)
		return &empty.Empty{}, err

	} else {
		return guildC.Apply(roleC.GetRole(roleID), req.Value)
	}
}

func (s *GuildService) AgreeApply(ctx context.Context, req *pb.Int32Slice) (reply *pb.GuildReply, err error) {

	reply = &pb.GuildReply{}

	var roleID = s.GetRoleID(ctx)
	var serverID = s.GetServerID(ctx)
	var guildID = s.GetGuildID(ctx)

	if guildID == 0 {
		return reply, errors.ParamError
	}

	member, err := guildC.GetMember(roleID, serverID, guildID)
	if err != nil {
		return reply, err
	}

	if member.Position < pb.GuildPosition_VicePresident {
		return reply, errors.ParamError
	}

	applyRoles, err := guildC.GetAppliesByID(req.Slices)
	if err != nil {
		return reply, err
	}

	var roles = map[int32]*pb.Role{}
	for _, v := range applyRoles {
		v.ServerID = serverID
		roles[v.RoleID] = v
	}

BREAK:
	for _, ID := range req.Slices {
		var _, err = guildC.DelApply(roleID, serverID, guildID, []int32{ID})
		if err == nil {

			for _, v := range applyRoles {
				if v.UserID == ID {

					if _, err = guildC.Join(roles[v.RoleID], guildID); err != nil {
						break BREAK
					}
				}
			}
		}
	}

	reply.Guild, _ = guildC.MyGuild(roleID, serverID, guildID)
	reply.Members, _ = guildC.Members(serverID, guildID)
	return reply, nil
}

// 拒绝入会
func (s *GuildService) RefuseApply(ctx context.Context, req *pb.Int32Slice) (*empty.Empty, error) {

	var roleID = s.GetRoleID(ctx)
	var serverID = s.GetServerID(ctx)
	var guildID = s.GetGuildID(ctx)

	var reply empty.Empty

	if guildID == 0 {
		return &reply, errors.ParamError
	}

	var res, err = guildC.DelApply(roleID, serverID, guildID, req.Slices)
	if err != nil {
		return res, err
	}

	applyRoles, err := guildC.GetAppliesByID(req.Slices)
	if err != nil {
		return &reply, err
	}

	var roleIDs []int32

	for _, v := range applyRoles {
		roleIDs = append(roleIDs, v.RoleID)
	}

	_ = mailC.Send(roleIDs, "您的入会申请被拒绝", "您的入会申请被拒绝", nil)

	return &reply, nil
}

func (s *GuildService) GetBosses(ctx context.Context, req *empty.Empty) (*pb.GuildBosses, error) {

	return guildC.GuildService.GetBosses(ctx, req)
}

func (s *GuildService) GetBoss(ctx context.Context, req *wrappers.Int32Value) (*pb.GuildBoss, error) {

	var bosses, err = guildC.GuildService.GetBosses(ctx, &empty.Empty{})
	if err != nil {
		return &pb.GuildBoss{}, err
	}

	for _, v := range bosses.Bosses {
		if v.BossID == req.Value {
			return v, nil
		}
	}

	return nil, nil
}

func (s *GuildService) OpenBoss(ctx context.Context, req *wrappers.Int32Value) (*pb.GuildBoss, error) {

	return guildC.GuildService.OpenBoss(ctx, req)
}

func (s *GuildService) AttackBoss(ctx context.Context, req *pb.GuildAttackBossRequest) (*pb.GuildAttackBossResp, error) {

	var roleID = s.GetRoleID(ctx)

	var captain = captainC.GetCaptain(roleID, req.CaptainID)

	var res, err = guildC.GuildService.AttackBoss(ctx, &service.GuildAttackBossRequest{BossID: req.BossID, CaptainID: req.CaptainID, Damage: captain.Power})
	if err == nil && res.Success && res.HP == 0 {

		var role = roleC.GetRole(roleID)
		_ = models.SendAward(role, res.Award)
	}

	return res, err
}
func (s *GuildService) BossRanking(ctx context.Context, req *wrappers.Int32Value) (*pb.GuildBossRankingReply, error) {

	var reply pb.GuildBossRankingReply

	var res, err = guildC.GuildService.Ranking(ctx, req)
	if err != nil {
		return &reply, err
	}

	var roleIDs = make([]int32, 0, len(res.GuildBossRecords))
	for _, v := range res.GuildBossRecords {
		roleIDs = append(roleIDs, v.RoleID)
	}

	var roles = roleC.GetRoles(roleIDs)

	reply.Ranking = make([]*pb.GuildBossRanking, 0, len(res.GuildBossRecords))
	for k, v := range res.GuildBossRecords {

		reply.Ranking = append(reply.Ranking, &pb.GuildBossRanking{
			Role:   roles[v.RoleID],
			Number: int32(k + 1),
			Damage: v.Damage,
			Points: v.Points,
		})
	}

	return &reply, nil
}

// 查看
func (s *GuildService) BossAwards(ctx context.Context, req *wrappers.Int32Value) (*pb.GuildBossAwardResp, error) {

	return guildC.GuildService.BossAwards(ctx, req)
}

// 领奖
func (s *GuildService) GetBossAward(ctx context.Context, req *pb.GuildGetBossAwardRequest) (*pb.Award, error) {

	var reply = &pb.Award{}

	var roleID = s.GetRoleID(ctx)
	var guildID = s.GetGuildID(ctx)

	if guildID == 0 {
		return reply, errors.ParamError
	}

	var boss, err = guildC.GuildService.GetBoss(ctx, &wrappers.Int32Value{Value: req.BossID})
	if err != nil {
		return reply, err
	}

	var role = roleC.GetRole(roleID)
	reply = models.RandAward(role, boss.AwardID)

	if _, err = guildC.GuildService.SetBossAward(ctx,
		&service.SetBossAwardRequest{Award: &pb.GuildBossAward{Role: role, Award: reply}, BossID: req.BossID, Index: req.Index}); err != nil {
		return nil, err
	}

	return reply, models.SendAward(role, reply)
}

// 恢复船长出战次数
func (*GuildService) Resurrection(ctx context.Context, req *wrappers.Int32Value) (*pb.ResurrectionResp, error) {

	return guildC.GuildService.Resurrection(ctx, req)
}

func (*GuildService) AttackMessages(ctx context.Context, req *empty.Empty) (*pb.GuildAttackMessages, error) {

	return guildC.GuildService.AttackMessages(ctx, req)
}

func (*GuildService) Record(ctx context.Context, req *empty.Empty) (*pb.GuildRecords, error) {

	return guildC.GuildService.Record(ctx, req)
}

func (*GuildService) GetSkills(ctx context.Context, req *empty.Empty) (*pb.GuildSkills, error) {

	return guildC.GuildService.GetSkills(ctx, req)
}

func (*GuildService) UpSkill(ctx context.Context, req *wrappers.Int32Value) (*pb.GuildUpSkillResp, error) {

	return guildC.GuildService.UpSkill(ctx, req)
}

func (*GuildService) GetDailyQuestAward(ctx context.Context, req *wrappers.Int32Value) (*pb.Award, error) {

	return guildC.GuildService.GetDailyQuestAward(ctx, req)
}
